//
//  TSCMyGCSelector.m
//  Tsc_IOS
//
//  Created by ZhengRui on 15/8/14.
//  Copyright © 2015年 idream. All rights reserved.
//
// == 使用说明
// 1. 使用时，必须先后执行以下两个方法
//   [gcSelector drawUI];
//   [gcSelector setupViewData_1];
// 2. 如果有ui设置类属性，需要在调用上述两个方法前设置，否则无效。因为drawUI()中需要用到这些ui设置类属性
//
// == TODO
// 1. 当_llAddGCPanel中的行全部删空时，由于_hlsBottom的top和_llAddGCPanel的bottom之间的padding还在，所以会显示多余的空白

#import <Foundation/Foundation.h>
#import "TSCMyGCSelector.h"
#import "TSCSDK.h"


#define MAX_GC_NUM 3 // 非设置项！最大可选商品分类数量
#define MAX_SP_NUM 3 // 非设置项！最大商品分类级别（即spinner的最大个数）

@implementation TSCMyGCSelector {
    UILabel * _lbIntro; // 首行说明文字（不包括右侧添加按钮）
    TSCMyClickBtn * _btnAddGC;
    TSCLinearLayout * _llAddGCPanel;
    UIView * _hlsBottom;
    
    NSInteger _selectorRows; // 当前界面上有多少个商品分类选择器
    
    NSString * _allAvailableGCIds; // 如果传入了aAvailableGCIds，则找到所有可选择的商品分类id。这些id可能是aAvailableGCIds中的父类、爷爷类
    
    // 首次从APP_DB中读取的一、二、三级商品分类。最大支持三级
    NSArray * _jsonGCList1; // 一级分类的全部商品分类，如果没有则为null
    
    NSInteger _spIdxGCId2DArr [MAX_GC_NUM][MAX_SP_NUM]; // 注：如果数组元素没有初始化，通过下标依然可以访问（甚至超出下标），但得到的值无意义
}

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        
        // 自定义初始化方法
        [self initGCSelector];
    }
    return self;
}

- (id) init {
    //    self = [super init];
    //    if (self) {
    //
    //        // 自定义初始化
    //      [self myInit2];
    //    }
    // 注：通过自身的initWithFrame，将初始化入口都定为initWithFrame，可以保证myInit只被调用一次
    self = [self initWithFrame:CGRectMake(0, 0, 0, 0)];
    return self;
}


// 注：该方法不能与父类LinerLayout（后简称LL）中的方法myInit同名！因为调用[super init]时，此时代码虽然运行在父类LL中，但self指向的对象其实还是子类GCSelector（OC机制就是这样，无法避免。我已经通过3层继承试验过）。所以当在父类LL中调用[self myInit]时，其实调用的是子类的myInit（其实就是方法重写），但当前上下文中，应该调用父类LL的myInit。而在父类LL中不能写成[super myInit]，因为父类LL的父类是UIView，而UIView没有myInit方法。为了解决这一问题，只能将子类中的同名方法换一个名字。并且将来如果还有孙子类继承GCSelector，也要注意这个问题，还得换另一个名字。
/* private */ - (void) initGCSelector {
    // 如果调用了没有任何参数的构造函数，则所有属性赋值默认值
    _maxRows = 0; // 先设置为0，后续读取APP_DB中的配置
    _availableGCIds = @"";
    _selectedGCIds = @"";
    
    _uiElementHeight = 30.0f;
    _uiFontSize = [TSCMyUIUtil getSystemDefaultFont].pointSize;
    _uiPadding = UI_ICON_PADDING;
    
    _selectorRows = 0;
    
    // 因oc中没有初始化的primitve数组的值是无效的，所以需要手工初始化
    for (NSInteger i = 0; i < MAX_GC_NUM; i++) {
        for (NSInteger j = 0; j < MAX_SP_NUM; j++) {
            _spIdxGCId2DArr[i][j] = 0;
        }
    }
    
    // ===== 创建UI元素
    // 注：通过外部使用者手工调用drawUI()来完成
    
}


#pragma mark 私有方法

/**
 * 过滤aMaxRows。注：
 * <p>
 * 1. 每一次重新设置aMaxRows后，都需要调用此方法
 */
/* private */ - (NSInteger) filterMaxRows:(NSInteger)maxRows {
    if (maxRows < 0) {
        // 记录log并提示错误
        NSLog(@"[w]%s:aMaxRows不能小于0（等于0时使用系统默认值）！将使用系统默认值代替错误值", __FUNCTION__);
        [TSCMyUIUtil popErrWithResourceKey:@"err_system_gc_selector"];
        NSDictionary * dic = [TSCMyDBUtil getSysConfigValueBatch_1:[NSArray arrayWithObject:DB_SYS_CONFIG_KEY_MAX_SELECTABLE_GOODS_CLASS]];
        return [[dic objectForKey:DB_SYS_CONFIG_KEY_MAX_SELECTABLE_GOODS_CLASS] integerValue];
    } else if (maxRows == 0) {
        NSDictionary * dic = [TSCMyDBUtil getSysConfigValueBatch_1:[NSArray arrayWithObject:DB_SYS_CONFIG_KEY_MAX_SELECTABLE_GOODS_CLASS]];
        return [[dic objectForKey:DB_SYS_CONFIG_KEY_MAX_SELECTABLE_GOODS_CLASS] integerValue];
    } else {
        return maxRows;
    }
}

/**
 * 公共过滤方法：对aAvailableGCIds、aSelectedGCIds进行过滤。注：
 * <p>
 * 1. 每一次重新设置aAvailableGCIds或aSelectedGCIds后，都需要调用此方法
 */
/* private */ - (NSString *) filterGCIds_1:(NSString *)gcIds {
    if ([TSCMyUtil isStringEmpty:gcIds] == true) {
        return @"";
    }
    
    NSString * tn = DB_TABLE_NAME_GOODS_CLASS;
    
    // （1）检查：状态为启用+存在于APP_DB中
    // 将所有status符合要求的id选出，并放在数组中
    NSString * sql = [NSString stringWithFormat:
                      @"SELECT id FROM %@ WHERE status = %li AND id IN (%@);",
                      tn,
                      DB_GOODS_CLASS_STATUS_IN_USE,
                      gcIds
                      ];
    NSArray * idDicArray = [TSCMyDBHelper selectWithSql:sql];
    NSMutableArray * statusAvailableIdArray = [NSMutableArray array];
    for (NSDictionary * idDic in idDicArray) {
        [statusAvailableIdArray addObject:[idDic objectForKey:@"id"]];
    }
    // 按原排列顺序创建id数组
    NSMutableArray * inIdArray = [NSMutableArray arrayWithArray:[TSCMyUtil explodeString:gcIds delimiter:@","]];
    // 对原有id序列中的每一个id，如果该id不在符合条件的id集合中，则剔除
    for (NSString * Id in inIdArray) {
        if ([statusAvailableIdArray containsObject:Id] == NO) {
            [inIdArray removeObject:Id];
        }
    }
    
    // （2）检查：不能是4级及以下级的商品分类
    sql = [NSString stringWithFormat:
           @"SELECT A3.id FROM %@ AS A3, %@ AS A2, %@ AS A1 WHERE A3.pid = A2.id AND A2.pid = A1.id AND A1.pid != 0;",
           tn,
           tn,
           tn
           ];
    NSArray * excludeIdDicArray = [TSCMyDBHelper selectWithSql:sql];
    for (NSDictionary * excludeIdDic in excludeIdDicArray) {
        NSObject * Id = [excludeIdDic objectForKey:@"id"] ;
        if ([inIdArray containsObject:Id]) {
            // 注：这里移除的应该是对象，而不是从位置为index的地方移除元素
            [inIdArray removeObject:Id];
        }
    }
    
    // （3）检查：不能再含有子分类
    // 注：过滤时，不要把pid为3级分类的情况也过滤掉了。因为虽然某个3级分类包含4级分类，但这个3级分类也是合法的（可被选择的）
    sql = [NSString stringWithFormat:
           @"SELECT pid FROM %@ WHERE pid IN (%@) AND pid NOT IN (%@) GROUP BY pid;",
           tn,
           [TSCMyUtil implodeWithGlue:@"," array:inIdArray],
           // -- 嵌套：找到所有3级分类id，将其排除在外
           [NSString stringWithFormat:@"SELECT A3.id AS id FROM %@ AS A3, %@ AS A2, %@ AS A1 WHERE A3.pid = A2.id AND A2.pid = A1.id AND A1.pid = 0", tn, tn, tn]
           ];
    NSArray * excludePidDicArray = [TSCMyDBHelper selectWithSql:sql];
    for (NSDictionary * excludePidDic in excludePidDicArray) {
        NSObject * pid = [excludePidDic objectForKey:@"pid"];
        if ([inIdArray containsObject:pid]) {
            // 注：这里移除的应该是对象，而不是从位置为index的地方移除元素
            [inIdArray removeObject:pid];
        }
    }
    
    return [TSCMyUtil implodeWithGlue:@"," array:inIdArray];
}

/**
 * 检查aSelectedGCIds是否大于aMaxRows。注：
 * <p>
 * 此方法必须在过滤了aAvailableGCIds、aSelectedGCIds之后再调用
 */
/* private */ - (void) checkMaxRowsLargerSelectedGCIds {
    // 注：当设置了默认被选项时，才进行校验
    if ([TSCMyUtil isStringEmpty:_selectedGCIds] == false) {
        NSArray * selectedIdArr = [TSCMyUtil explodeString:_selectedGCIds delimiter:@","];
        
        if ([selectedIdArr count] > _maxRows) {
            NSLog(@"[W]%s: aSelectedGCIds的数量不能大于aMaxRows！将清除aSelectedGCIds", __FUNCTION__);
            _selectedGCIds = @"";
            [TSCMyUIUtil popErrWithResourceKey:@"err_system_gc_selector"];
        }
    }
}

/**
 * 检查aSelectedGCIds是否是aAvailableGCIds的子集
 */
/* private */ - (void) checkSelectedGCIdsInAvailableGCIds {
    // 注：当设置了默认被选项、且设置了选择范围时，才进行校验
    if ([TSCMyUtil isStringEmpty:_selectedGCIds] == false && [TSCMyUtil isStringEmpty:_availableGCIds] == false) {
        NSArray * selectedIdArr = [TSCMyUtil explodeString:_selectedGCIds delimiter:@","];
        NSArray * availableIdArr = [TSCMyUtil explodeString:_availableGCIds delimiter:@","];
        if ([TSCMyUtil isA:selectedIdArr subsetOfB:availableIdArr] == false) {
            NSLog(@"[W]%s: aSelectedGCIds必须是aAvailableGCIds的子集！将清除aSelectedGCIds", __FUNCTION__);
            _selectedGCIds = @"";
            [TSCMyUIUtil popErrWithResourceKey:@"err_system_gc_selector"];
        }
    }
}


/* private */ - (void) addSelectorRowEmpty {
    
    // ===== 创建一行选择器
    
    // 创建ll
    UIView * selectorRow = [[UIView alloc]init];
    
    // 创建3个sp
    TSCMySpinner * sp1 = [[TSCMySpinner alloc]init];
    TSCMySpinner * sp2 = [[TSCMySpinner alloc]init];
    TSCMySpinner * sp3 = [[TSCMySpinner alloc]init];
    sp1.font = sp2.font = sp3.font = [UIFont fontWithName:[TSCMyUIUtil getSystemDefaultFont].fontName size:_uiFontSize];
    
    // 创建删除按钮
    TSCMyClickBtn * btnDelGC = [TSCMyClickBtn buttonWithType:UIButtonTypeSystem];  // 确保点击时产生阴影
    [btnDelGC setImage:[UIImage imageNamed:@"ic_err_96x96.png" ] forState:UIControlStateNormal];
    
    // 添加到界面
    [selectorRow addSubview:sp1];
    [selectorRow addSubview:sp2];
    [selectorRow addSubview:sp3];
    [selectorRow addSubview:btnDelGC];
    [_llAddGCPanel addSubview:selectorRow];
  
    // 添加约束
    // selectorRow
    // 注：不要给selectorRow（LinearLayout的直接子view）添加任何约束
    // sp1
    sp1.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|[sp1(sp3)]-%f-[sp2(sp3)]-%f-[sp3][btnDelGC(%f)]|", _uiPadding, _uiPadding, _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp1, sp2, sp3, btnDelGC)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp1(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp1)]];
    // sp2
    sp2.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp2(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp2)]];
    // sp3
    sp3.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp3(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp3)]];
    // 删除按钮
    btnDelGC.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[btnDelGC(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(btnDelGC)]];
    
    // 仅显示第一个sp
    sp1.hidden = NO;
    sp2.hidden = YES;
    sp3.hidden = YES;
    
    // 注册事件——删除按钮
    btnDelGC.btnClickedListener = ^(TSCMyClickBtn * btn) {
        [selectorRow removeFromSuperview]; // 品类选择view所在的父view也是固定的
        
        // 更新计数
        _selectorRows--;
        
        // 判断是否需要显示底部的分隔符
        if (_selectorRows == 0) {
            _llAddGCPanel.hidden = YES; // 因为c_2_f的约束也有高度，所以也得隐藏
            _hlsBottom.hidden = YES;
        }
    };
    
    // 更新计数
    _selectorRows++;
    
    // 判断是否需要显示底部的分隔符
    if (_selectorRows > 0) {
        _llAddGCPanel.hidden = NO;
        _hlsBottom.hidden = NO;
    }
}

/* private */ - (void) addSelectorRowUnselected {
    
    // 增加一行选择器
    UIView * selectorRow = [[UIView alloc]init];
    
    // 创建3个sp
    TSCMySpinner * sp1 = [[TSCMySpinner alloc]init];
    TSCMySpinner * sp2 = [[TSCMySpinner alloc]init];
    TSCMySpinner * sp3 = [[TSCMySpinner alloc]init];
    sp1.font = sp2.font = sp3.font = [UIFont fontWithName:[TSCMyUIUtil getSystemDefaultFont].fontName size:_uiFontSize];
    
    // 创建删除按钮
    TSCMyClickBtn * btnDelGC = [TSCMyClickBtn buttonWithType:UIButtonTypeSystem];  // 确保点击时产生阴影
    [btnDelGC setImage:[UIImage imageNamed:@"ic_err_96x96.png" ] forState:UIControlStateNormal];
    
    // 添加到界面
    [selectorRow addSubview:sp1];
    [selectorRow addSubview:sp2];
    [selectorRow addSubview:sp3];
    [selectorRow addSubview:btnDelGC];
    [_llAddGCPanel addSubview:selectorRow];
    
    // 添加约束
    // selectorRow
    // 注：不要给selectorRow（LinearLayout的直接子view）添加任何约束
    // sp1
    sp1.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|[sp1(sp3)]-%f-[sp2(sp3)]-%f-[sp3][btnDelGC(%f)]|", _uiPadding, _uiPadding, _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp1, sp2, sp3, btnDelGC)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp1(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp1)]];
    // sp2
    sp2.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp2(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp2)]];
    // sp3
    sp3.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp3(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp3)]];
    // 删除按钮
    btnDelGC.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[btnDelGC(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(btnDelGC)]];
    
    // 注册事件——删除此行品类选择器
    btnDelGC.btnClickedListener = ^(TSCMyClickBtn * btn) {
        [selectorRow removeFromSuperview]; // 品类选择view所在的父view也是固定的
        
        // 更新计数
        _selectorRows--;
        
        // 判断是否需要显示底部的分隔符
        if (_selectorRows == 0) {
            _llAddGCPanel.hidden = YES; // 因为c_2_f的约束也有高度，所以也得隐藏
            _hlsBottom.hidden = YES;
        }
    };
    
    
    // 注册事件——1级分类变化时，自动获取其下所有2级分类
    [self registerSpinner1Events:sp1 sp2:sp2 sp3:sp3];
    
    // 注册事件——2级分类变化时，自动获取其下所有3级分类
    [self registerSpinner2Events:sp1 sp2:sp2 sp3:sp3];
    
    // 注册事件——3级分类变化时，在整行选择器上保存选择了哪一个商品分类
    [self registerSpinner3Events:sp1 sp2:sp2 sp3:sp3];
    
    // 初始化sp1。sp2、sp3将因为OnItemSelectedListener()事件而自动选择
    [self setSpinnerAdapter:sp1 jsonGCList:_jsonGCList1];
    
    // 更新计数
    _selectorRows++;
    
    // 判断是否需要显示底部的分隔符
    if (_selectorRows > 0) {
        _llAddGCPanel.hidden = NO;
        _hlsBottom.hidden = NO;
    }
}

/* private */ - (void) addSelectorRowSelected:(NSInteger[3]) spIdxGcIdArr {
    
    // 增加一行选择器
    UIView * selectorRow = [[UIView alloc]init];
    
    // 创建3个sp
    TSCMySpinner * sp1 = [[TSCMySpinner alloc]init];
    TSCMySpinner * sp2 = [[TSCMySpinner alloc]init];
    TSCMySpinner * sp3 = [[TSCMySpinner alloc]init];
    sp1.font = sp2.font = sp3.font = [UIFont fontWithName:[TSCMyUIUtil getSystemDefaultFont].fontName size:_uiFontSize];
    
    // 注册事件——删除此行品类选择器
    TSCMyClickBtn * btnDelGC = [TSCMyClickBtn buttonWithType:UIButtonTypeSystem];  // 确保点击时产生阴影
    [btnDelGC setImage:[UIImage imageNamed:@"ic_err_96x96.png" ] forState:UIControlStateNormal];
    
    // 添加到界面
    [selectorRow addSubview:sp1];
    [selectorRow addSubview:sp2];
    [selectorRow addSubview:sp3];
    [selectorRow addSubview:btnDelGC];
    [_llAddGCPanel addSubview:selectorRow];
    
    // 添加约束
    // selectorRow
    // 注：不要给selectorRow（LinearLayout的直接子view）添加任何约束
    // sp1
    sp1.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|[sp1(sp3)]-%f-[sp2(sp3)]-%f-[sp3][btnDelGC(%f)]|", _uiPadding, _uiPadding, _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp1, sp2, sp3, btnDelGC)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp1(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp1)]];
    // sp2
    sp2.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp2(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp2)]];
    // sp3
    sp3.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[sp3(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(sp3)]];
    // 删除按钮
    btnDelGC.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[btnDelGC(%f)]|", _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(btnDelGC)]];
    
    // 注册事件——删除此行品类选择器
    btnDelGC.btnClickedListener = ^(TSCMyClickBtn * btn) {
        [selectorRow removeFromSuperview]; // 品类选择view所在的父view也是固定的
        
        // 更新计数
        _selectorRows--;
        
        // 判断是否需要显示底部的分隔符
        if (_selectorRows == 0) {
            _llAddGCPanel.hidden = YES; // 因为c_2_f的约束也有高度，所以也得隐藏
            _hlsBottom.hidden = YES;
        }
    };
    
   
    // 获得3个商品分类id
    NSInteger selectedGCId1 = spIdxGcIdArr[0];
    NSInteger selectedGCId2 = spIdxGcIdArr[1];
    NSInteger selectedGCId3 = spIdxGcIdArr[2];
    
    // 处理sp1
    if (selectedGCId1 != 0) {
        // 找到sp1选择item对应的全部二级商品分类
        // 注：mJsonGCList1在之前初始化过
        
        // 填充sp
        [self setSpinnerAdapter:sp1 jsonGCList:_jsonGCList1];
        
        // 找到gcId在spinner中对应的itemIdex
        NSInteger selectedItemIndex = 0;
        for (NSInteger i = 0, max = [_jsonGCList1 count]; i < max; i++) {
            if (((TSCJsonGC *)[_jsonGCList1 objectAtIndex:i]).Id == selectedGCId1) {
                selectedItemIndex = i;
                break;
            }
        }
        
        // 在sp中选择指定的item
        [sp1 setSelectedItem:selectedItemIndex];
        
        // 在整行选择器上保存商品分类id
        selectorRow.myTag = [NSNumber numberWithLong:selectedGCId1];
    } else {
        // selectedGCId1一定不为0
    }
    
    // 处理sp2
    if (selectedGCId2 != 0) {
        // 找到sp1选择item对应的全部二级商品分类
        NSArray * jsonGCList2 = [TSCMyDBUtil getGoodsClassAllChildrenInUse_1:selectedGCId1 availableGCIds:_allAvailableGCIds];
        
        // 填充sp
        [self setSpinnerAdapter:sp2 jsonGCList:jsonGCList2];
        
        // 找到gcId在spinner中对应的itemIdex
        NSInteger selectedItemIndex = 0;
        for (NSInteger i = 0, max = [jsonGCList2 count]; i < max; i++) {
            if (((TSCJsonGC *)[jsonGCList2 objectAtIndex:i]).Id == selectedGCId2) {
                selectedItemIndex = i;
                break;
            }
        }
        
        // 在sp中选择指定的item
        [sp2 setSelectedItem:selectedItemIndex];
        
        // 在整行选择器上保存商品分类id
        selectorRow.myTag = [NSNumber numberWithLong:selectedGCId2];
    } else {
        sp2.hidden = YES;
    }
    
    // 处理sp3
    if (selectedGCId3 != 0) {
        // 找到sp1选择item对应的全部二级商品分类
        NSArray * jsonGCList3 = [TSCMyDBUtil getGoodsClassAllChildrenInUse_1:selectedGCId2 availableGCIds:_allAvailableGCIds];
        
        // 填充sp
        [self setSpinnerAdapter:sp3 jsonGCList:jsonGCList3];
        
        // 找到gcId在spinner中对应的itemIdex
        NSInteger selectedItemIndex = 0;
        for (NSInteger i = 0, max = [jsonGCList3 count]; i < max; i++) {
            if (((TSCJsonGC *)[jsonGCList3 objectAtIndex:i]).Id == selectedGCId3) {
                selectedItemIndex = i;
                break;
            }
        }
        
        // 在sp中选择指定的item
        [sp3 setSelectedItem:selectedItemIndex];
        
        // 在整行选择器上保存商品分类id
        selectorRow.myTag = [NSNumber numberWithLong:selectedGCId3];
    } else {
        sp3.hidden = YES;
    }
    
    // 注册事件
    // 注意：一定要在填充完sp之后才能注册事件，否则会导致在填充sp时，就触发事件，引起不必要的混乱
    // 注：因注册事件放在设置sp之后，所以，当selectedGCId1/2/3为0时，需要将其隐藏（不同于Android）
    // 如果仅仅只是注册事件的代码放在setSelection()之后是没有用的，必须使用post()方法才能保证注册事件在setSelection()之后（仅Android）
    
    // 注册事件——1级分类变化时，自动获取其下所有2级分类
    [self registerSpinner1Events:sp1 sp2:sp2 sp3:sp3];
    // 注册事件——2级分类变化时，自动获取其下所有3级分类
    [self registerSpinner2Events:sp1 sp2:sp2 sp3:sp3];
    // 注册事件——3级分类变化时，在整行选择器上保存选择了哪一个商品分类
    [self registerSpinner3Events:sp1 sp2:sp2 sp3:sp3];
    
    
    // 更新计数
    _selectorRows++;
    
    // 判断是否需要显示底部的分隔符
    if (_selectorRows > 0) {
        _llAddGCPanel.hidden = NO;
        _hlsBottom.hidden = NO;
    }
}


/**
 * 注册事件——1级分类变化时，自动获取其下所有2级分类
 *
 * @param sp1
 * @param sp2
 * @param sp3
 */
/* private */ - (void) registerSpinner1Events:(TSCMySpinner *)sp1 sp2:(TSCMySpinner *)sp2 sp3:(TSCMySpinner *)sp3 {
    sp1.itemSelectedListener = ^(TSCMySpinner * sp, UITableViewCell * cell, NSIndexPath * ip) {
        // 获得tag
        TSCJsonGC * jsonGC = (TSCJsonGC *) cell.myTag;
        
        // 在整行选择器上保存商品分类id
        // 注（安卓）：此时，view是spinner中的item：textview；parent是spinner本身；parent.getParent()是整行选择器
        // 注（IOS）：spinner的parent就是整行选择器
        UIView * selectorRow = (UIView *) sp.superview;
        selectorRow.myTag = [NSNumber numberWithLong:jsonGC.Id];
        
        // 重新设置2级分类
        NSArray * jsonGCArray2 = [TSCMyDBUtil getGoodsClassAllChildrenInUse_1:jsonGC.Id availableGCIds:_allAvailableGCIds];
        [self setSpinnerAdapter:sp2 jsonGCList:jsonGCArray2];
        
        // 如果2级分类为空时，2级分类的OnItemSelectedListener事件不会自动触发，则需要通过代码（安卓如此，IOS的MySpinner是自己写的：当dataArray为空时，不会进行自动选择，也是如此。所以可以推测，安卓的Spinner代码写法，跟我的写法应该是一样的）
        // 隐藏3级分类
        if ([jsonGCArray2 count] == 0) {
            [self setSpinnerAdapter:sp3 jsonGCList:nil]; // 直接隐藏3级分类选择器
        }
    };
}

/**
 * 注册事件——2级分类变化时，自动获取其下所有3级分类
 *
 * @param sp1
 * @param sp2
 * @param sp3
 */
/* private */ - (void) registerSpinner2Events:(TSCMySpinner *)sp1 sp2:(TSCMySpinner *)sp2 sp3:(TSCMySpinner *)sp3 {
    sp2.itemSelectedListener = ^(TSCMySpinner * sp, UITableViewCell * cell, NSIndexPath * ip) {
        // 获得tag
        TSCJsonGC * jsonGC = (TSCJsonGC *) cell.myTag;
        
        // 在整行选择器上保存商品分类id
        // 注：此时，view是spinner中的item：textview；parent是spinner本身；parent.getParent()是整行选择器
        // 注（IOS）：spinner的parent就是整行选择器
        UIView * selectorRow = (UIView *) sp.superview;
        selectorRow.myTag = [NSNumber numberWithLong:(jsonGC.Id)];
        
        // 重新设置3级分类
        NSArray * jsonGCArray3 = [TSCMyDBUtil getGoodsClassAllChildrenInUse_1:jsonGC.Id availableGCIds:_allAvailableGCIds];
        [self setSpinnerAdapter:sp3 jsonGCList:jsonGCArray3];
    };
}

/**
 * 注册事件——3级分类变化时，在整行选择器上保存选择了哪一个商品分类
 *
 * @param sp1
 * @param sp2
 * @param sp3
 */
/* private */ - (void) registerSpinner3Events:(TSCMySpinner *) sp1 sp2:(TSCMySpinner *)sp2 sp3:(TSCMySpinner *)sp3 {
    sp3.itemSelectedListener = ^(TSCMySpinner * sp, UITableViewCell * cell, NSIndexPath * ip) {
        // 获得tag
        TSCJsonGC * jsonGC = (TSCJsonGC *) cell.myTag;
        
        // 在整行选择器上保存商品分类id
        // 注：此时，view是spinner中的item：textview；parent是spinner本身；parent.getParent()是整行选择器
        // 注（IOS）：spinner的parent就是整行选择器
        UIView * selectorRow = (UIView *) sp.superview;
        selectorRow.myTag = [NSNumber numberWithLong:jsonGC.Id];
    };
}

/* private */ - (void) setSpinnerAdapter:(TSCMySpinner * )spinner jsonGCList:(NSArray *)jsonGCList {
    // 如果数据源有数据，则显示并设置adapter
    if (jsonGCList != nil && [jsonGCList count] != 0) {
        // 注：因调用此方法的后续代码需要立即得到spinner填充数据后的值，所以不使用异步线程准备数据
        //        [spinner prepareData_P1:^{
        //            // 获得商品分类名称
        //            NSMutableArray * gcNameArray = [NSMutableArray array];
        //            for (TSCJsonGC * jsonGC in jsonGCList) {
        //                [gcNameArray addObject:jsonGC.name];
        //            }
        //
        //            [spinner.dataArray addObjectsFromArray:gcNameArray];
        //        } completionHandler:^{
        //            [spinner applyData];
        //        }];
        
        // 将tag保存在每一个cell上
        spinner.cellModifier = ^(UITableView * tv, UITableViewCell * cell, NSIndexPath *ip) {
            TSCJsonGC * jsonCG = [jsonGCList objectAtIndex:ip.row];
            cell.myTag = jsonCG;
        };
        
        // 获得商品分类名称
        NSMutableArray * gcNameArray = [NSMutableArray array];
        for (TSCJsonGC * jsonGC in jsonGCList) {
            [gcNameArray addObject:jsonGC.name];
        }
        spinner.dataArray = [NSMutableArray arrayWithArray:gcNameArray];
        [spinner applyData];
        
        spinner.hidden = NO;
    }
    // 如果数据源无数据，则隐藏
    else {
        spinner.hidden = YES;
    }
}


#pragma mark 公共方法

/**
 * 根据UI类设置属性，绘制各UI元素
 *
 * @author Rio
 * @date 2015-08-18
 */
/* public */ - (void) drawUI {
    // 创建顶部：左侧label
    _lbIntro = [[UILabel alloc]init];
    _lbIntro.font = [UIFont fontWithName:[TSCMyUIUtil getSystemDefaultFont].fontName size:_uiFontSize];
    _lbIntro.text = NSLocalizedString(@"hint_select_goods_class", nil);
    [self addSubview:_lbIntro];
    
    // 创建顶部：右侧按钮
    _btnAddGC = [TSCMyClickBtn buttonWithType:UIButtonTypeSystem]; // 确保点击时产生阴影
    [_btnAddGC setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [_btnAddGC setTitle:NSLocalizedString(@"btn_plus", nil) forState:UIControlStateNormal];
    _btnAddGC.titleLabel.font = [UIFont fontWithName:[TSCMyUIUtil getSystemDefaultFont].fontName size:_uiFontSize];
    _btnAddGC.backgroundColor = COLOR_MT;
    [TSCMyUIUtil setUIRoundRectBG:_btnAddGC radius:10.0]; // 设置圆形按钮
    [self addSubview:_btnAddGC];
    
    // 注册事件——增加商品分类选择器
    __weak typeof (self) _weakSelf = self;
    _btnAddGC.btnClickedListener = ^(TSCMyClickBtn * btn) {
        typeof (self) _strongSelf = _weakSelf;
        if (_strongSelf) {
            // 检查是否超过最大行数限制
            if (_strongSelf->_selectorRows >= _strongSelf->_maxRows) {
                NSString * msg = [NSString stringWithFormat:@"%@%li%@", NSLocalizedString(@"err_exceed_max_selectable_goods_class_1", nil),_strongSelf->_maxRows, NSLocalizedString(@"err_exceed_max_selectable_goods_class_2", nil)];
                [TSCMyUIUtil popErrWithString:msg];
                return;
            }
            
            // 增加一个空行
            [_weakSelf addSelectorRowUnselected];
        } else {
            NSLog(@"[W]%s: block中的弱引用为nil，导致block内部代码无法正常执行！", __FUNCTION__);
        }
    };
    
    // 创建顶部分割线
    UIView * hlsTop = [[UIView alloc]init];
    hlsTop.backgroundColor = COLOR_MT;
    [self addSubview:hlsTop];
    
    // 创建中部
    _llAddGCPanel = [[TSCLinearLayout alloc]init];
    _llAddGCPanel.orientation = LINEAR_LAYOUT_ORIENTATION_VERTICAL;
    _llAddGCPanel.paddingC2C = _uiPadding; // 设置每一行上下之间的距离
    [self addSubview:_llAddGCPanel];
    
    // 创建底部分割线
    _hlsBottom = [[UIView alloc]init];
    _hlsBottom.backgroundColor = COLOR_MT;
    [self addSubview:_hlsBottom];
    
    // 设置各UI元素的约束
    // 左侧label
    _lbIntro.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-%f-[_lbIntro][_btnAddGC(%f)]-%f-|", _uiPadding, _uiElementHeight, _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_lbIntro,_btnAddGC)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|-%f-[_lbIntro(%f)]", _uiPadding, _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_lbIntro)]];
    // 右侧按钮
    _btnAddGC.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|-%f-[_btnAddGC(%f)]", _uiPadding, _uiElementHeight] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_btnAddGC)]];
    // 顶部分割线
    hlsTop.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-%f-[hlsTop]-%f-|", _uiPadding, _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(hlsTop)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[_lbIntro]-%f-[hlsTop(1)]", _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_lbIntro, hlsTop)]];
    // 中部
    _llAddGCPanel.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-%f-[_llAddGCPanel]-%f-|", _uiPadding, _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_llAddGCPanel)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[hlsTop]-%f-[_llAddGCPanel]", _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(hlsTop, _llAddGCPanel)]]; // 注：不指定高度，是因为高度会随行数变化而变化
    // 底部分割线
    _hlsBottom.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-%f-[_hlsBottom]-%f-|", _uiPadding, _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_hlsBottom)]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[_llAddGCPanel]-%f-[_hlsBottom(1)]-%f-|", _uiPadding, _uiPadding] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_llAddGCPanel, _hlsBottom)]];
    
    // 增加一个空行
    [self addSelectorRowEmpty];
}


/**
 * 依照各属性，从APP_DB中给商品分类选择器填充数据。
 *
 * @author Rio
 * @date 2014-11-06
 */
/* public */ - (void) setupViewData_1 {
    // 过滤并检查各参数
    _maxRows = [self filterMaxRows:_maxRows];
    _availableGCIds = [self filterGCIds_1:_availableGCIds];
    _selectedGCIds = [self filterGCIds_1:_selectedGCIds];
    [self checkMaxRowsLargerSelectedGCIds];
    [self checkSelectedGCIdsInAvailableGCIds];
    
    // 如果指定了可选商品分类id的范围，则需选出所有可选商品分类的父类、爷爷类，作为“合法的”商品分类id范围
    if ([TSCMyUtil isStringEmpty:_availableGCIds] == false) {
        _allAvailableGCIds = [TSCMyDBUtil getAllAvailableGCIds_1:_availableGCIds];
    } else {
        _allAvailableGCIds = @""; // 赋空值表示没有可选集的限定，所有商品分类都可以选择
    }
    
    // 如果指定了默认被选择的商品分类，则需要选出各个初始时被选择商品分类的父类别、爷爷类别
    // 注：这里无需按照1级商品分类再对mSpIdxGCId2DArr的各行进行排序，只要保证一个spinner中的各个item是按照商品分类的seq升序排列即可
    if ([TSCMyUtil isStringEmpty:_selectedGCIds] == false) {
        [TSCMyDBUtil getSpIdxGCId2DArr_1:_spIdxGCId2DArr gcIds:_selectedGCIds];
    }
    
    // 针对于点击“增加”按钮新增的一行商品分类选择器，初始时应该如何填充，后续代码选出默认的一级、二级、三级分类
    // 选出所有1级分类（支持限定id范围）
    _jsonGCList1 = [TSCMyDBUtil getGoodsClassTopLevelInUse_1:_allAvailableGCIds];
    
    // 创建并显示选择器行
    
    // 清空所有已存在的选择器行
    [TSCMyUIUtil removeAllSubviews:_llAddGCPanel];
    _selectorRows = 0;
    
    // 指定了初始时选择的商品分类
    if ([TSCMyUtil isStringEmpty:_selectedGCIds] == false) {
        for (NSInteger i = 0, max = arr_count(_spIdxGCId2DArr); i < max; i++) {
            // 注：即便初始时没有指定任何已经选择的商品分类，_spIdxGCId2DArr依然是一个具有3个元素（每一个元素都是一个数组）的数组，不能显示空行
            if (_spIdxGCId2DArr[i][0] != 0) {
                [self addSelectorRowSelected:_spIdxGCId2DArr[i]];
            }
        }
    }
    // 没有指定初始时选择的商品分类
    else {
        [self addSelectorRowUnselected];
    }
}

/**
 * 将用户选择的全部商品分类id以String的形式返回，后续将可能发送server
 *
 * @author Rio
 * @date 2014-11-06
 * @return 输出格式为：1,3,21
 */
/* public */ - (NSString *) getSelectedGCIdsStr {
    NSMutableString * sb = [[NSMutableString alloc]init];
    
    // 循环处理每一行的商品分类选择器
    NSInteger rows = [_llAddGCPanel.subviews count];
    for (NSInteger i = 0; i < rows; i++) {
        // 这一行最高级别（最精确）的商品分类id，就保存在这一行的tag上
        UIView * llSelectorRow = (UIView *) [_llAddGCPanel.subviews objectAtIndex:i];
        NSNumber * tag = (NSNumber *) llSelectorRow.myTag;
        
        if (tag != nil) {
            NSInteger goodsClassId = [tag intValue];
            
            if (i < rows - 1) {
                [sb appendString:[NSString stringWithFormat:@"%li,", goodsClassId]];
            } else {
                [sb appendString:[NSString stringWithFormat:@"%li", goodsClassId]];
            }
        } else {
            // do nothing
            // 没有设置tag，可能是初始时增加了空行
        }
    }
    
    return sb;
}


/**
 * 将用户选择的全部商品分类name以list形式返回。同一行选择器中的所有spinner值，作为返回ArrayList中的一个元素。
 * 假设最多可选3个分类，且每行分类包含多级分类，可能的一种返回是：
 * <p>
 * gcName1/gcName2/gcName3
 * <p>
 * gcName4
 * <p>
 * gcName5/gcName6
 *
 * @author Rio
 * @date 2014-11-08
 * @return
 */
/* public */ - (NSArray *) getSelectedGCNameList {
    NSMutableArray * list = [NSMutableArray array];
    
    // 循环处理每一行的商品分类选择器
    // NSInteger rows = mLlAddGcPanel.getChildCount();
    for (NSInteger i = 0; i < _selectorRows; i++) {
        UIView * llSelectorRow = (UIView *) [_llAddGCPanel.subviews objectAtIndex:i];
        
        // 找到这一行的全部spinner
        TSCMySpinner * sp1 = (TSCMySpinner *) [llSelectorRow.subviews objectAtIndex:0];
        TSCMySpinner * sp2 = (TSCMySpinner *) [llSelectorRow.subviews objectAtIndex:1];
        TSCMySpinner * sp3 = (TSCMySpinner *) [llSelectorRow.subviews objectAtIndex:2];
        
        // 拼装这一行的全部分类名称（支持多级）
        // 注：仅处理显示（存在）的spinner
        // 注：仅当1存在，2才可能存在；仅当2存在，3才可能存在
        NSMutableString * sb = [[NSMutableString alloc]init];
        if (sp1.hidden == NO) {
            NSString * gcName1 = (NSString *) [sp1 getSelectedObject];
            [sb appendString:gcName1];
            
            if (sp2.hidden == NO) {
                NSString * gcName2 = (NSString *) [sp2 getSelectedObject];
                [sb appendString:[NSString stringWithFormat:@"/%@", gcName2]];
                
                if (sp3.hidden == NO) {
                    NSString * gcName3 = (NSString *) [sp3 getSelectedObject];
                    [sb appendString:[NSString stringWithFormat:@"/%@", gcName3]];
                }
            }
        }
        
        [list addObject:sb];
    }
    
    return list;
}

/**
 * 将商品分类名称list转换为商品分类名称描述性字符串（一个商品分类占据一行）。格式：
 * <p>
 * 1. 女鞋/女船鞋/女黑船鞋
 * <p>
 * 2. 男鞋
 * <p>
 * 3. 婴幼儿用品
 *
 * @author Rio
 * @date 2014-11-15
 *
 * @param gcNamesList
 * @return
 */
/* public */ + (NSString *) gcNameList2GcNameStr:(NSArray *) gcNamesList {
    NSMutableString * sb = [[NSMutableString alloc]init];
    
    // 只有一行时，不显示序号
    if ([gcNamesList count] == 1) {
        [sb appendString: [gcNamesList objectAtIndex:0]];
    }
    // 当有多行时，显示序号，并换行
    else {
        for (NSInteger i = 0, max = [gcNamesList count]; i < max; i++) {
            // 显示商品分类名称（带换行符）
            if (i == 0) {
                [sb appendString:[NSString stringWithFormat:@"%li.%@", i + 1, [gcNamesList objectAtIndex:i]]];
            } else {
                [sb appendString:[NSString stringWithFormat:@"\n%li.%@", i + 1, [gcNamesList objectAtIndex:i]]];
            }
        }
    }
    
    return sb;
}

/**
 * 通过gcIds，获得这些商品分类名称的描述性字符串（一个商品分类占据一行）。格式：
 * <p>
 * 1. 女鞋/女船鞋/女黑船鞋
 * <p>
 * 2. 男鞋
 * <p>
 * 3. 婴幼儿用品
 *
 * @author Rio
 * @date 2014-11-15
 *
 * @return 如果gcIds为空字符串，则返回空字符串；否则，返回对应的商品分类名称（s）字符串
 */
/* public */ + (NSString *) gcIds2GcPathNameStr_1:(NSString *) gcIds {
    if ([TSCMyUtil isStringEmpty:gcIds] == true) {
        return @"";
    } else {
        // 获得sp下标与商品分类信息的2维数组
        NSArray * spIdxGC2DArr = [TSCMyDBUtil getSpIdxGC2DArr_1:gcIds];
        
        // 拼装商品分类名称，格式：
        // 女鞋/船鞋/平底船鞋
        // 女装/连衣裙
        // 男装
        NSMutableString * sb = [[NSMutableString alloc]init];
        // TDDO spIdxGC2DArr有可能为nil
        for (NSInteger i = 0, max = [spIdxGC2DArr count]; i < max; i++) {
            // 换行符
            if (i != 0) {
                [sb appendString:@"\r\n"];
            }
            
            NSArray * row = [spIdxGC2DArr objectAtIndex:i];
            
            for (NSInteger j = 0, max2 = [row count]; j < max2; j++) {
                TSCJsonGC * gc = (TSCJsonGC *) [row objectAtIndex:j];
                
                // 找到一个要显示的商品分类
                if (gc != nil) {
                    if (j == 0) {
                        [sb appendString:gc.name];
                    } else {
                        [sb appendString:[NSString stringWithFormat:@"/%@", gc.name]];
                    }
                }
            }
        }
        
        return sb;
        
        // 注：以下代码废弃，不能使用MyGoodsClassSelector重新构造，因为其中有代码是运行在UI线程上的，将导致线程同步问题
        // // 获得商品分类的数量
        // String[] gcIdArr = MyUtil.explode(",", gcIds);
        
        // // 构造一个临时的商品分类选择器，以便通过这个临时的商品分类选择器，获得已被选中商品分类的名称
        // MyGoodsClassSelector gcSelector = new
        // MyGoodsClassSelector(context,
        // // maxRows：必须等于被选择商品分类的数量
        // gcIdArr.length,
        // // availableGCIds：空字符串
        // "",
        // // selectedGCIds
        // gcIds);
        // gcSelector.setupViewData_1();
        
        // 获得并返回
        // return MyGoodsClassSelector.gcNameList2GcNameStr(gcSelector
        // .getSelectedGCNameList());
    }
}

/**
 * 通过gcIds，获得这些商品分类名称的描述性字符串（一个商品分类占据一行）。格式：
 * <p>
 * 1. 女黑船鞋
 * <p>
 * 2. 男鞋
 * <p>
 * 3. 婴幼儿用品
 *
 * @author Rio
 * @date 2014-12-10
 *
 * @return 如果gcIds为空字符串，则返回空字符串；否则，返回对应的商品分类名称字符串
 */
/* public */ + (NSString *) gcIds2GcSingleNameStr_1:(NSString *)gcIds {
    if ([TSCMyUtil isStringEmpty:gcIds] == true) {
        return @"";
    } else {
        NSMutableString * sb = [[NSMutableString alloc]init];
        NSArray * gcIdStrArr = [TSCMyUtil explodeString:gcIds delimiter:@","];
        for (NSInteger i = 0, max = [gcIdStrArr count]; i < max; i++) {
            TSCJsonGC * jsonGC = [TSCMyDBUtil getGC_1:[[gcIdStrArr objectAtIndex:i] intValue]];
            
            if (i != 0) {
                [sb appendString:@","];
            }
            
            [sb appendString:jsonGC.name];
        }
        
        return sb;
    }
}

/**
 * 从UI界面上清除所有已选择的商品分类行，以确保在后续getSelectedGCNameList()等方法中，选出空list
 *
 * @author Rio
 * @date 2014-12-08
 */
/* public */ - (void) cleanSelectedRows {
    // 清空所有已存在的选择器行
    [TSCMyUIUtil removeAllSubviews:_llAddGCPanel];
    _selectorRows = 0;
}



@end